#include "Filter.h"

void img_Clone(HXLBMPFILE &src, HXLBMPFILE &des)
{
	int i, j;
	des.imagew = src.imagew;	 // 长度
	des.imageh = src.imageh;	 // 宽度
	des.iYRGBnum = src.iYRGBnum; // 位数
	if (des.iYRGBnum == 1)
	{
		//对灰度图需复制调色板
		for (i = 0; i < 256; i++)
		{
			des.palette[i] = src.palette[i];
		}
	}
	if (!des.AllocateMem())
	{
		printf("ERROR!\n");
		exit(1);
	}
	if (des.iYRGBnum == 1)
	{
		for (i = 0; i < des.imagew; i++)
			for (j = 0; j < des.imageh; j++)
				des.pDataAt(i)[j] = src.pDataAt(i)[j];
	}
	else
	{
		for (i = 0; i < des.imagew; i++)
			for (j = 0; j < des.imageh; j++)
			{
				des.pDataAt(i, 0)[j] = src.pDataAt(i, 0)[j];
				des.pDataAt(i, 1)[j] = src.pDataAt(i, 1)[j];
				des.pDataAt(i, 2)[j] = src.pDataAt(i, 2)[j];
			}
	}
}

void addSaltNoise(HXLBMPFILE &src, int n)
{
	for (int k = 0; k < n; k++)
	{
		// 随机取值行列
		int i = rand() % src.imagew;
		int j = rand() % src.imagew;
		// 图像通道判定
		if (src.iYRGBnum == 1)
		{
			src.pDataAt(i)[j] = 255; // 盐噪声
		}
		else
		{
			src.pDataAt(i, 0)[j] = 255;
			src.pDataAt(i, 1)[j] = 255;
			src.pDataAt(i, 2)[j] = 255;
		}
	}
	for (int k = 0; k < n; k++)
	{
		// 随机取值行列
		int i = rand() % src.imagew;
		int j = rand() % src.imagew;
		// 图像通道判定
		if (src.iYRGBnum == 1)
		{
			src.pDataAt(i)[j] = 0; // 椒噪声
		}
		else
		{
			src.pDataAt(i, 0)[j] = 0;
			src.pDataAt(i, 1)[j] = 0;
			src.pDataAt(i, 2)[j] = 0;
		}
	}
	src.SaveBMPFILE("./output/SaltNoise.bmp");
}

void Spatialfilter(HXLBMPFILE &src, HXLBMPFILE &des, float *w, int m, int n)
{
	// 没有做边界延拓
	int i, j, s, t;
	int A = (m - 1) / 2, B = (n - 1) / 2; // 模板下标的边界值
	float r = 0, g = 0, b = 0;
	for (i = A; i <= src.imagew - A; i++)
		for (j = B; j <= src.imageh - B; j++) // 对目标图像的每个像素
		{
			r = 0, g = 0, b = 0; // 目标图像当前位置像素值，置零
			if (src.iYRGBnum == 1)
			{
				for (s = -A; s <= A; s++)
					for (t = -B; t <= B; t++) // 对模板范围内的"像素值*模板权值"求和
					{
						r += (float)src.pDataAt(i + s)[j + t] * w[(s + A) * m + (t + B)];
					}
				if (r < 0) // 注意r应在0-255之间
					r = 0;
				r = (int)r % 256;
				des.pDataAt(i)[j] = (BYTE)r;
			}
			else
			{
				for (s = -A; s <= A; s++)
					for (t = -B; t <= B; t++) // 对模板范围内的"像素值*模板权值"求和
					{
						r += (float)src.pDataAt(i + s, 0)[j + t] * w[(s + A) * m + (t + B)];
						g += (float)src.pDataAt(i + s, 1)[j + t] * w[(s + A) * m + (t + B)];
						b += (float)src.pDataAt(i + s, 2)[j + t] * w[(s + A) * m + (t + B)];
					}
				if (r < 0)
					r = 0;
				if (g < 0)
					g = 0;
				if (b < 0)
					b = 0;
				r = (int)r % 256;
				g = (int)g % 256;
				b = (int)b % 256;
				des.pDataAt(i, 0)[j] = (BYTE)r;
				des.pDataAt(i, 1)[j] = (BYTE)g;
				des.pDataAt(i, 2)[j] = (BYTE)b;
			}
		}
	des.SaveBMPFILE("./output/FiltedImage.bmp");
}

void Spatialfilter(HXLBMPFILE &bmpfile, float *W, int M, int N)
{
	HXLBMPFILE bf;
	img_Clone(bmpfile, bf);

	int A = (M - 1) / 2, B = (N - 1) / 2;
	int i, j, s, t;
	float r = 0, g = 0, b = 0;
	if (bmpfile.iYRGBnum == 1)
	{
		for (j = A; j <= bmpfile.imagew - A; j++)
			for (i = B; i <= bmpfile.imageh - B; i++)
			{
				r = 0;
				for (s = -A; s <= A; s++)
					for (t = -B; t <= B; t++)
						r += (float)bmpfile.pDataAt(j + s)[i + t] *
							 W[(s + A) * M + (t + B)];
				if (r < 0)
					r = 0;
				r = (int)r % 256;
				bf.pDataAt(j)[i] = (BYTE)r;
			}
	}
	else if (bmpfile.iYRGBnum == 3)
	{
		for (j = A; j <= bmpfile.imageh - A; j++)
			for (i = B; i <= bmpfile.imagew - B; i++)
			{

				r = g = b = 0;
				for (s = -A; s <= A; s++)
					for (t = -B; t <= B; t++)
					{
						r += (float)bmpfile.pDataAt(j + s, 0)[i + t] *
							 W[(s + A) * M + (t + B)];
						g += (float)bmpfile.pDataAt(j + s, 1)[i + t] *
							 W[(s + A) * M + (t + B)];
						b += (float)bmpfile.pDataAt(j + s, 2)[i + t] *
							 W[(s + A) * M + (t + B)];
					}
				if (r < 0)
					r = 0;
				if (g < 0)
					g = 0;
				if (b < 0)
					b = 0;
				r = (int)r % 256;
				g = (int)g % 256;
				b = (int)b % 256;
				bf.pDataAt(j, 0)[i] = (BYTE)r;
				bf.pDataAt(j, 1)[i] = (BYTE)g;
				bf.pDataAt(j, 2)[i] = (BYTE)b;
				// printf("r=%.0f ",r);
			}
	}
	bf.SaveBMPFILE("./output/FilterImage.bmp");
	return;
}

float find_mid(float *r, int m, int n)
{
	int i, j;
	float temp;
	for (i = 1; i < m * n; i++) //直接插入排序
	{
		temp = r[i]; //哨兵位复制当前值
		for (j = i - 1; temp < r[j]; --j)
		{
			r[j + 1] = r[j]; //记录后移
		}
		r[j + 1] = temp; //插入到正确位置
	}
	return r[(int)(m * n / 2 + 0.5)];
}

void Medianfilter(HXLBMPFILE &src, HXLBMPFILE &des, float *w, int m, int n)
{
	int i, j, s, t;
	int A = (m - 1) / 2, B = (n - 1) / 2; // 模板下标的边界值
	int num = 0;						  // 计算求中值的数组中有多少元素
	for (i = 0; i < m * n; i++)
		num += w[i];
	float *r, *g, *b;
	r = (float *)malloc(num * sizeof(float)); // 中值数组
	b = (float *)malloc(num * sizeof(float));
	g = (float *)malloc(num * sizeof(float));
	for (i = A; i < src.imagew - A; i++)
		for (j = B; j < src.imageh - B; j++) // 对目标图像的每个像素
		{
			memset(r, 0, num); // 中值数组置零
			memset(g, 0, num);
			memset(b, 0, num);
			if (src.iYRGBnum == 1) // 对于灰度图像只需要排序取中值
			{
				int index = 0;
				for (s = -A; s <= A; s++)
					for (t = -B; t <= B; t++) // 按照模板取像素值，保存到中值数组中
					{
						if (w[(s + A) * m + (t + B)] == 1) // 如果该像素只出现一次
						{
							r[index] = (float)src.pDataAt(i + s)[j + t];
							index++;
						}
						else
						{
							for (int n = 0; n < w[(s + A) * m + (t + B)]; n++)
							{
								r[index] = (float)src.pDataAt(i + s)[j + t];
								index++;
							}
						}
					}
				des.pDataAt(i)[j] = (BYTE)find_mid(r, m, n);
			}
			else // 对于彩图我们分别对RGB求中值
			{

				int index = 0;
				for (s = -A; s <= A; s++)
					for (t = -B; t <= B; t++) // 按照模板取像素值，保存到中值数组中
					{
						if (w[(s + A) * m + (t + B)] == 1) // 如果该像素只出现一次
						{
							r[index] = (float)src.pDataAt(i + s, 0)[j + t];
							g[index] = (float)src.pDataAt(i + s, 1)[j + t];
							b[index] = (float)src.pDataAt(i + s, 2)[j + t];
							index++;
						}
						else
						{
							for (int n = 0; n < w[(s + A) * m + (t + B)]; n++)
							{
								r[index] = (float)src.pDataAt(i + s, 0)[j + t];
								g[index] = (float)src.pDataAt(i + s, 1)[j + t];
								b[index] = (float)src.pDataAt(i + s, 2)[j + t];
								index++;
							}
						}
					}
				des.pDataAt(i, 0)[j] = (BYTE)find_mid(r, m, n);
				des.pDataAt(i, 1)[j] = (BYTE)find_mid(g, m, n);
				des.pDataAt(i, 2)[j] = (BYTE)find_mid(b, m, n);
			}
		}
	des.SaveBMPFILE("./output/Medianfilter.bmp");
	free(r);
	free(g);
	free(b);
}